//=============================================================================
// XBus 
//-----------------------------------------------------------------------------
// File        : xbus_init.c
// Description : 
// Author      : Ismail Sabry
// Date        : 1/30/2009
//=============================================================================

#include <xbus.h>
#include <xbus_shm.h>
#include <xbus_module.h>
#include <xbus_cell.h>
#include <xbus_init.h>

#define XBUS_DISPLAY_INFO  1

//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
unsigned int XBUS_get_size(t_XBUS_info *info)
{
  unsigned int   sz_xbus, sz_module, sz_cell;
  
  sz_cell   = sizeof(t_XBUS_cell_header)   + (info->size_cell);
  sz_module = sizeof(t_XBUS_module_header) + (info->nb_cell   *   sz_cell);
  sz_xbus   = sizeof(t_XBUS_header)        + (info->nb_module * sz_module);
  
  info->size = sz_xbus;

#if XBUS_DISPLAY_INFO
  printf("\n");
  printf("XBus Configuration \n");
  printf("  Name ........... : %s \n", info->name);
  printf("  Nb Modules ..... : %d (%d Bytes) \n", info->nb_module, sz_module);
  printf("  Nb Cells ....... : %d (%d Bytes) \n", info->nb_cell, sz_cell);
  printf("  Cell Payload ... : %d \n", info->size_cell);
  printf("  Size ........... : %d Bytes \n", info->size );
  printf("\n");
#endif

  return(info->size);
}

//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
int XBUS_create(t_XBUS_info *info)
{
  if( XBUS_get_size(info) > XBUS_MAX_SIZE) {
    printf("XBus too large %d (max %d) \n", info->size, XBUS_MAX_SIZE);
    return -1;
  }
  
  if(XBUS_create_shm(info->name, info->size, &info->addr) == -1) {
    return -1;
  }

  info->xbus = (t_XBUS *)info->addr;
  
  XBUS_init(info);
  
  return 0;
}

//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
int XBUS_remove(t_XBUS_info *info)
{
  XBUS_remove_shm(info->name, info->addr);
  return 0;
}

//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
int XBUS_init(t_XBUS_info *info)
{
  int            i, j;
  t_XBUS         *xbus;
  t_XBUS_module  *module;
  t_XBUS_cell    *cell, *next;
  
  xbus = info->xbus;
  
  // init path header 
  xbus->head.magictag       = XBUS_MAGICTAG_XBUS;
  
  xbus->head.version.major  = XBUS_VERSION;
  xbus->head.version.minor  = XBUS_RELEASE;
  xbus->head.version.change = XBUS_CHANGE;

  snprintf(xbus->head.name, XBUS_SIZE_NAME-1, "%s", info->name);
  
  xbus->head.nb_module      = info->nb_module;
  xbus->head.nb_cell        = info->nb_cell;
  xbus->head.size_cell      = info->size_cell;
  xbus->head.size           = info->size;

  // init modules
  for(i=0; i<info->nb_module; i++) {
    // init module(i) 
    module = XBUS_get_module_by_index(xbus, i);
    XBUS_init_module(module);
    
    // init module cells
    for(j=0; j<info->nb_cell; j++) {
      // init cell(j)
      cell = XBUS_get_cell_by_index(xbus, module, j);
      XBUS_init_cell(cell);
    }

    for(j=0; j<info->nb_cell; j++) {
      // link cell(j)->cell(j+1)
      cell = XBUS_get_cell_by_index(xbus, module, j);
      next = XBUS_get_cell_by_index(xbus, module, (j+1)%info->nb_cell);
      XBUS_chain_cell(cell, next);
    }
  }

  return 0;
}
